#include "mainwindow.h"
#include "XMysqlConnect.h"
#include "imagerecover.h"
#include "printer.h"
#include "openssl/obj_mac.h"
#include "qmenu.h"
#include "steganographyOnImage.h"
#include "ui_form_fwjg.h"
#include "ui_form_recover.h"
#include "ui_mainwindow.h"
#include "XLogger.h"
#include <QRect>
#include <QFileDialog>
#include <QPixmap>
#include <QTabWidget>
#include <QToolBar>
#include <random>
#include <QScrollArea>
#include <QLayout>
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
    ,m_shared(std::shared_ptr<EC_GROUP>(EC_GROUP_new_by_curve_name(NID_sm2),
                                      [](EC_GROUP* group){
                                          if(group){EC_GROUP_free(group);}
                                      }))
    ,buttonGroup(this)
{
    ui->setupUi(this);
    XLogger* logger=XLogger::init();
    if(!m_shared.m_group)
    {
        logger->setDevice(XLogger::T_FILE);
        logger->outPut([this](std::string& s){ui->textEdit_XiaoXi->append(QString::fromStdString(s));},std::string("椭圆曲线设置失败"),std::string("./logInfo.log"),XLogger::L_ERROR);
    }
    logger->setDevice(XLogger::T_CONSILE);

    connect(&fwjg,&Form_fwjg::sharedSignal,this,&MainWindow::fwjgShared);//
    connect(&recover,&Form_recover::closeSignal,this,&MainWindow::recoverRecover);//

    ui->textEdit_XiaoXi->setReadOnly(true);

    setWindowIcon(QIcon(":/icon/imageSharedIcon.png"));

    ui->stackedWidget->insertWidget(0,&fwjg);
    ui->stackedWidget->insertWidget(1,&recover);
    ui->stackedWidget->setCurrentIndex(0);

    fwjg.setTextEdit(ui->textEdit_XiaoXi);
    recover.setTextEdit(ui->textEdit_XiaoXi);

    buttonGroup.addButton(ui->pushButton_recover);
    ui->pushButton_shared->setChecked(true);
    buttonGroup.addButton(ui->pushButton_shared);
    buttonGroup.addButton(ui->pushButton_steganography);
    buttonGroup.setExclusive(true);

    buttonGroupXiaoXi.addButton(ui->pushButton_XiaoXiLan);
    buttonGroupXiaoXi.addButton(ui->pushButton_cuowu);
    buttonGroupXiaoXi.addButton(ui->pushButton_CanShu);
    buttonGroupXiaoXi.addButton(ui->pushButton_JingGao);
    buttonGroupXiaoXi.setExclusive(true);

    ui->widget_xiaoxilan->setVisible(true);
    ui->pushButton_XiaoXiLan->setChecked(true);
    printer=Printer::init();
    printer->setLevel(Printer::L_INFO);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::mousePressEvent(QMouseEvent *event){
    if(event->button()==Qt::LeftButton){
        if(ui->label_image->underMouse()){
            on_pushButton_open_clicked();
        }
    }
}

void MainWindow::fwjgShared(){
    //是否选择了图片
    if(m_shared.m_image.isNull()){
        printer->print(ui->textEdit_XiaoXi,"未选择图片！",Printer::L_INFO);
        return;
    }
    //是否设置参与人数
    if(fwjg.participantCount<=0){
        printer->print(ui->textEdit_XiaoXi,"未设置参与人数与访问结构！",Printer::L_INFO);
        return;
    }
    //是否设置参访问结构
    if(fwjg.fwjgCount<=0){
        printer->print(ui->textEdit_XiaoXi,"错误：未设置访问结构！",Printer::L_INFO);
        return;
    }
    //保存路径
    auto savePos=QFileDialog::getExistingDirectory(nullptr,"保存路径");
    if(savePos.isEmpty()){
        printer->print(ui->textEdit_XiaoXi,"错误：未选择存储位置！",Printer::L_INFO);
        return;
    }
    auto cnt=getPubInfoCount(m_sql);
    if(cnt.isEmpty()){
        QDateTime dateTime= QDateTime::currentDateTime();//获取系统当前的时间
        cnt=dateTime .toString("yyyy-MM-dd hh:mm:ss");//格式化时间
    }
    this->savePos=std::move(savePos);
    //打印访问结构即相关信息
    printFwjg();
    //分发图像
    QVector<uint> setR=QVector<uint>(fwjg.participantCount);
    for(int i=0;i<fwjg.participantCount;++i){
        setR[i]=i+1;
    }
    m_shared.setImage(imagePos);
    //生成随机分组组数
    std::random_device rd;
    std::default_random_engine eng(rd());
    std::uniform_int_distribution<int> distr(128, 256);
    auto shadowTem = m_shared.getShadow(fwjg.participantCount,distr(eng));
    if(shadowTem.empty()){
        printer->print(ui->textEdit_XiaoXi,"影子图像生成失败！");
        return;
    }
    auto pubInfo=m_shared.getPubInfo(shadowTem,setR,fwjg.accessStructure);
    if(pubInfo.isEmpty()){
        printer->print(ui->textEdit_XiaoXi,"公共信息生成失败！");
        return;
    }
    auto name=cnt+"_"+fInfo.baseName()+"_pubInfo.json";
    bool ret=m_shared.savePubInfo("./pubInfos/"+name,pubInfo);
    if(!ret){
        printer->print(ui->textEdit_XiaoXi,"公共信息保存失败！");
        return;
    }
    auto met=getMethod(fwjg.ui->comboBox_shared->currentIndex());
    ret=m_shared.saveShadow(shadowTem,this->savePos,*fwjg.ui->tableWidget_cyz,met,fwjg.carIamgePos);
    if(!ret){
        printer->print(ui->textEdit_XiaoXi,"子秘密保存失败！");
        return;
    }
    printer->print(ui->textEdit_XiaoXi,"子秘密保存成功！子秘密保存路径："+this->savePos);
    //在数据库保存数据
    savePubInfoToMysql(name,cnt);
}

void MainWindow::recoverRecover()
{
    if(recover.cnt<=0){
        printer->print(ui->textEdit_XiaoXi,"未选择子秘密！",Printer::L_INFO);
        return;
    }
    if(recover.setNum<=0){
        printer->print(ui->textEdit_XiaoXi,"未设置授权集合编号！",Printer::L_INFO);
        return;
    }
    if(recover.pubInfoPos.isNull()){
        printer->print(ui->textEdit_XiaoXi,"未选择授公共信息！",Printer::L_INFO);
        return;
    }
    imageRecover ire{m_shared.m_group};
    bool ret=ire.setPubInfo(recover.pubInfoPos);
    if(!ret){
        printer->print(ui->textEdit_XiaoXi,"公共信息打开失败或公共信息错误！",Printer::L_ERROR);
        return;
    }
    QVector<QByteArrayList> frxs;
    auto met=getMethod(recover.ui->comboBox_recover->currentIndex());
    for(int i=0;i<recover.cnt;++i){
        auto imageFilePos=recover.ui->tableWidget_selects->item(i,0)->text();
        frxs.append(ire.getFrx(recover.setNum-1,imageFilePos,met));
        if(frxs[i].isEmpty()){
            printer->print(ui->textEdit_XiaoXi,"公共信息与秘密图像不匹配！",Printer::L_ERROR);
            return;
        }
    }
    m_shared.m_image=m_shared.recover(frxs,ire.getJsonObject(),recover.setNum-1);
    ui->label_image->setPixmap(QPixmap::fromImage(m_shared.m_image));
    printer->print(ui->textEdit_XiaoXi,"恢复图像操作成功！",Printer::L_INFO);
}

void MainWindow::on_pushButton_shared_clicked()
{
    ui->stackedWidget->setCurrentIndex(0);
}

void MainWindow::on_pushButton_recover_clicked()
{
    ui->stackedWidget->setCurrentIndex(1);
}

void MainWindow::on_pushButton_steganography_clicked()
{
    ui->stackedWidget->setCurrentIndex(2);
}

void MainWindow::on_pushButton_open_clicked()
{
    // 打开文件对话框
    auto imagePos= QFileDialog::getOpenFileName(nullptr, QString("选择文件"),QDir::currentPath(), "图片文件 (*.png *.jpg *.jpeg *.bmp *.pgm *.pbm)",nullptr,QFileDialog::ShowDirsOnly);
    if (!imagePos.isEmpty()) {
        // 打印所选文件的路径
        m_shared.m_image=QImage(imagePos);
        fInfo=QFileInfo(imagePos);
        printer->print(ui->textEdit_XiaoXi,"打开图片："+imagePos);
        fwjg.imName=fInfo.baseName();
        fwjg.suffix=fInfo.suffix();
        ui->label_image->setPixmap(QPixmap::fromImage(m_shared.m_image));
        this->imagePos=std::move(imagePos);
    }
}

void MainWindow::readPubInfo()
{
    bool ret=m_sql->query("select num,pos from pub_info_num where num<30 order by num");
    if(!ret){
        printer->print(ui->textEdit_XiaoXi,"公开信息读取失败!");
        return;
    }
    while (m_sql->next()) {
        ui->listWidget_pub->addItem(QString::fromStdString(m_sql->value(1)));
    }
}

void MainWindow::printFwjg()
{
    printer->print(ui->textEdit_XiaoXi,"共享图片："+imagePos);
    printer->print(ui->textEdit_XiaoXi,"参与者人数："+QString::number(fwjg.participantCount));
    //打印影子图像名称
    ui->textEdit_XiaoXi->append("影子图像名称：");
    for(int i=0;i<fwjg.participantCount;++i){
        ui->textEdit_XiaoXi->append(QString("    ")+fwjg.ui->tableWidget_cyz->item(i,2)->text());
    }
    //打印访问结构
    ui->textEdit_XiaoXi->append("\n访问结构：{");
    auto n__=fwjg.accessStructure.size();
        for(int i=0;i<n__;++i){
            ui->textEdit_XiaoXi->insertPlainText("{");
            auto n_=fwjg.accessStructure[i].size();
            for(int j=0;j<n_;++j){
                ui->textEdit_XiaoXi->insertPlainText(fwjg.accessStructure[i][j]);
                if(j!=n_-1)
                    ui->textEdit_XiaoXi->insertPlainText(",");
            }
            ui->textEdit_XiaoXi->insertPlainText("}");
            if(i!=n__-1)
                ui->textEdit_XiaoXi->insertPlainText(",");
        }
        ui->textEdit_XiaoXi->insertPlainText("}\n");
}

void MainWindow::savePubInfoToMysql(QString &pubInfoName, QString str_cnt)
{
    m_sql->transaction();
    int cnt=str_cnt.toInt();
    auto s="update pub_info_cont set cnt="+std::to_string(cnt+1)+" where cnt="+std::to_string(cnt);
    bool re=m_sql->update(s);
    if(!re){
        printer->print(ui->textEdit_XiaoXi,"数据库公共信息数量跟新失败！",Printer::L_ERROR);
        m_sql->rollback();
        return;
    }
    auto pub="insert into pub_info_num(num,pos) value("+str_cnt.toStdString()+",\""+pubInfoName.toStdString()+"\")";
    re=m_sql->update(pub);
    if(!re){
        printer->print(ui->textEdit_XiaoXi,"数据库公共信息跟新失败！",Printer::L_ERROR);
        m_sql->rollback();
        return;
    }
    printer->print(ui->textEdit_XiaoXi,"数据库公共信息跟新成功！",Printer::L_INFO);
    m_sql->commit();
}

SaveMethod MainWindow::getMethod(int met)
{
    switch (met) {
    case 0://文本
        return SaveMethod::TXT;
    case 1://图片
        return SaveMethod::IMA;
    case 2://LSB
    {
        return SaveMethod::LSB;
    }
    case 3://EMD
        return SaveMethod::EMD;
    default:
        return SaveMethod::NON;
    }
}

QString MainWindow::getPubInfoCount(std::shared_ptr<XMysqlConnect> &Sql)
{
    bool re=Sql->query("select cnt from pub_info_cont");
    if(!re){
        printer->print(ui->textEdit_XiaoXi,"数据库公共信息数量查询失败！",Printer::L_ERROR);
        return QString();
    }
    if(!Sql->next()){
        return QString();
    }
    return QString::fromStdString(Sql->value(0));
}

void MainWindow::on_pushButton_save_clicked()
{
    QString fileName=QFileDialog::getSaveFileName(nullptr,QString("保存图片"),QDir::currentPath(),QString("图片 (*.png *.jpg *.jpeg *.bmp *.pgm *.pbm)"));
    if(m_shared.m_image.save(fileName)){
        printer->print(ui->textEdit_XiaoXi,"保存成功!");
        return;
    }
    printer->print(ui->textEdit_XiaoXi,"保存失败!");
}

void MainWindow::login(QString s,std::shared_ptr<XMysqlConnect> sql)
{
    m_sql=sql;
    this->show();
    ui->label_user_name->setText(s);
    readPubInfo();
}

void MainWindow::on_listWidget_pub_customContextMenuRequested(const QPoint &pos)
{
    //定义菜单类,listWidget控件为父类，作用就是把菜单和控件进行绑定
    QMenu m_menu ;
    QAction* act =m_menu.addAction("从本地选择公共信息");
    //执行菜单,菜单的位置在当前光标位置上
    QAction* cur=m_menu.exec(ui->listWidget_pub->mapToGlobal(pos));
    if(cur==act){
        auto pubInfoPos= QFileDialog::getOpenFileName(nullptr, QString("选择文件"),"./pubInfos", "public information (*.json)",nullptr,QFileDialog::ShowDirsOnly);
        if(pubInfoPos.isNull()){
            auto printer=Printer::init();
            printer->print(ui->textEdit_XiaoXi,"未选择公共信息!");
            return;
        }
        ui->listWidget_pub->addItem(QFileInfo(pubInfoPos).fileName());
    }
}

void MainWindow::on_pushButton_choice_clicked()
{
    int r=ui->listWidget_pub->currentRow();
    if(r<0){
        return;
    }
    recover.pubInfoPos="./pubInfos/"+ui->listWidget_pub->currentItem()->text();
    auto printer=Printer::init();
    printer->print(ui->textEdit_XiaoXi,"公共信息："+recover.pubInfoPos);
    ui->textEdit_canshu->setText(("公共信息："+recover.pubInfoPos));
}

void MainWindow::on_pushButton_CanShu_clicked()
{
    if(!ui->widget_xiaoxilan->isVisible()){
        ui->widget_xiaoxilan->setVisible(true);
    }
    ui->label_xiaoxilan->setText(" 参数");
    ui->stackedWidget_xiaoxi->setCurrentIndex(CANSHU);
}

void MainWindow::on_pushButton_cuowu_clicked()
{
    if(!ui->widget_xiaoxilan->isVisible()){
        ui->widget_xiaoxilan->setVisible(true);
    }
    ui->label_xiaoxilan->setText(" 错误");
    ui->stackedWidget_xiaoxi->setCurrentIndex(CUOWU);
}

void MainWindow::on_pushButton_JingGao_clicked()
{
    if(!ui->widget_xiaoxilan->isVisible()){
        ui->widget_xiaoxilan->setVisible(true);
    }
    ui->label_xiaoxilan->setText(" 警告");
    ui->stackedWidget_xiaoxi->setCurrentIndex(JINGAO);
}

void MainWindow::on_pushButton_XiaoXiLan_clicked()
{
    if(!ui->widget_xiaoxilan->isVisible()){
        ui->widget_xiaoxilan->setVisible(true);
    }
    ui->label_xiaoxilan->setText(" 消息");
    ui->stackedWidget_xiaoxi->setCurrentIndex(XIAOXI);
}

void MainWindow::on_pushButton_choice_car_clicked()
{
    auto imagePos= QFileDialog::getOpenFileName(nullptr, QString("选择文件"),QDir::currentPath(), "图片文件 (*.png *.jpg *.jpeg *.bmp *.pgm *.pbm)",nullptr,QFileDialog::ShowDirsOnly);
    if (imagePos.isEmpty()) {
        return;
    }
    carIamge=QImage(imagePos);
    ui->label_carIamge->setPixmap(QPixmap::fromImage(carIamge));
    auto printer=Printer::init();
    printer->log(ui->textEdit_XiaoXi,"载体图片"+imagePos);
}

void MainWindow::on_pushButton_hite_clicked()
{
    if(carIamge.isNull()||m_shared.m_image.isNull()){
        return;
    }
    QFile file{imagePos};
    auto printer=Printer::init();
    if(!file.open(QFile::ReadOnly)){
         printer->print(ui->textEdit_XiaoXi,"被隐藏图片打开失败！",Printer::Level::L_ERROR);
    }
    auto data=file.readAll();
    file.close();
    SteganographyOnImage::Method met=(SteganographyOnImage::Method)ui->comboBox_hite->currentIndex();
    auto ret=SteganographyOnImage::imbedded(carIamge,data,met);
    if(ret){
        auto imagePos= QFileDialog::getSaveFileName(nullptr,"保存文件","./","图片文件 (*.png *.bmp)");
        if(carIamge.save(imagePos))
            printer->print(ui->textEdit_XiaoXi,"隐藏并成功保存！",Printer::Level::L_INFO);
        else{
            printer->print(ui->textEdit_XiaoXi,"隐藏成功但保存失败！",Printer::Level::L_ERROR);
        }
        ui->label_carIamge->setPixmap(QPixmap::fromImage(carIamge));
        return;
    }
    printer->print(ui->textEdit_XiaoXi,"隐藏失败！",Printer::Level::L_ERROR);
}

void MainWindow::on_pushButton_extraction_clicked()
{
    if(carIamge.isNull()){
        return;
    }
    auto s=SteganographyOnImage::retrieval(carIamge);
    auto printer=Printer::init();
    if(!m_shared.m_image.loadFromData(s)){
        printer->print(ui->textEdit_XiaoXi,"提取失败！",Printer::Level::L_INFO);
        return;
    }
    ui->label_image->setPixmap(QPixmap::fromImage(m_shared.m_image));
    printer->print(ui->textEdit_XiaoXi,"提取成功！",Printer::Level::L_INFO);
}

void MainWindow::on_pushButton_xiaoxi_min_clicked()
{
    if(ui->widget_xiaoxilan->isVisible())
    {
        ui->widget_xiaoxilan->setVisible(false);
    }
    else{
        ui->widget_xiaoxilan->setVisible(true);
    }
}

//void MainWindow::on_textEdit__textChanged()
//{
//    ui->pushButton_XiaoXiLan->setStyleSheet(
//        R"(QPushButton{color:rgb(255, 100, 100);})"
//        );
//    ui->pushButton_XiaoXiLan->setStyleSheet(
//        R"(QPushButton{color:rgb(244, 244, 244);})"
//        );
//}

void MainWindow::on_pushButton_Search_clicked()
{
    auto text=ui->lineEdit_pub_serch->text().toStdString();
    if(text.empty()){
        return;
    }
    auto sql=R"(select pos from pub_info_num where pos like "%)"+text+R"(%")";
    bool ret=m_sql->query(sql);
    if(!ret){
        printer->print(ui->textEdit_,"数据库查询失败！",Printer::L_ERROR);
        return;
    }
    //定义菜单类,listWidget控件为父类，作用就是把菜单和控件进行绑定
    QMenu m_menu;
    int cnt=0;
    while(m_sql->next()){
        ++cnt;
        m_menu.addAction(QString::fromStdString(m_sql->value(0)));
    }
    QAction* err=cnt==0?m_menu.addAction("没有数据"):nullptr;
    //执行菜单,菜单的位置在当前光标位置上
    QAction* cur=m_menu.exec(ui->lineEdit_pub_serch->mapToGlobal(QPoint(0,ui->lineEdit_pub_serch->height())));
    if(cur&&cur!=err){
        auto pubInfoPos= cur->text();
        if(pubInfoPos.isNull()){
            auto printer=Printer::init();
            printer->print(ui->textEdit_XiaoXi,"未选择公共信息!");
            return;
        }
        ui->listWidget_pub->insertItem(0,QFileInfo(pubInfoPos).fileName());
        ui->listWidget_pub->setCurrentItem(ui->listWidget_pub->item(0));
//        recover.pubInfoPos="./pubInfos/"+pubInfoPos;
//        printer->print(ui->textEdit_XiaoXi,"公共信息："+pubInfoPos,Printer::L_INFO);
    }
}
